package com.wenbing.miio.util;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class CipherUtil {

    /**
     * md5加密
     * @param a
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static byte[] md5(byte[] a) throws NoSuchAlgorithmException {
        return MessageDigest.getInstance("MD5").digest(a);
    }

    /**
     * sha加密
     * @param a
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static byte[] sha(byte[] a) throws NoSuchAlgorithmException {
        return MessageDigest.getInstance("SHA").digest(a);
    }

    public static byte[] sha256(byte[] a) throws NoSuchAlgorithmException {
        return MessageDigest.getInstance("SHA-256").digest(a);
    }

    /**
     * AES CBC 加密
     * @param ivc
     * @param key
     * @param value
     * @param valOffset
     * @param valLen
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static byte[] aesCbc(byte[] ivc , byte[] key , byte[] value, int valOffset, int valLen) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        IvParameterSpec iv = new IvParameterSpec( ivc );
        SecretKeySpec sks = new SecretKeySpec(key , "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE , sks , iv);
        byte[] encrypted = cipher.doFinal(value, valOffset, valLen);
        return encrypted;
    }

    public static byte[] aesNoPadding(byte[] ivc , byte[] key , byte[] value) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        IvParameterSpec iv = new IvParameterSpec( ivc );
        SecretKeySpec sks = new SecretKeySpec(key , "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        int padding = 16 - value.length % 16;
        value = BytesUtils.marginArray(value, BytesUtils.repeat((byte) padding, padding));
        cipher.init(Cipher.ENCRYPT_MODE , sks , iv);
        byte[] encrypted = cipher.doFinal(value);
        return encrypted;
    }

    /**
     * AES CBC 加密
     * @param ivc
     * @param key
     * @param value
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static byte[] aesCbc(byte[] ivc , byte[] key , byte[] value) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        return aesCbc(ivc, key, value, 0, value.length);
    }

    /**
     * AES CBC 解密
     * @param ivc
     * @param key
     * @param value
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static byte[] deAesCbc(byte[] ivc , byte[] key , byte[] value) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        return deAesCbc(ivc, key, value, 0, value.length);
    }

    /**
     * AES CBC 解密
     * @param ivc
     * @param key
     * @param value
     * @param valOffset
     * @param valLen
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static byte[] deAesCbc(byte[] ivc , byte[] key , byte[] value, int valOffset, int valLen) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        IvParameterSpec iv = new IvParameterSpec( ivc );
        SecretKeySpec sks = new SecretKeySpec(key , "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE , sks , iv);
        byte[] encrypted = cipher.doFinal(value, valOffset, valLen);
        return encrypted;
    }


    public static byte[] random(int length) {
        byte[] bs = new byte[length];
        new Random().nextBytes(bs);
        return bs;
    }
}
